package jmcnet.libcommun.socketpool
{
	import flash.events.Event;
	import flash.events.TimerEvent;
	import flash.utils.Timer;
	
	import flexunit.framework.Assert;
	
	import jmcnet.libcommun.logger.JMCNetLog4JLogger;
	import jmcnet.libcommun.logger.JMCNetLogger;
	
	import org.flexunit.async.Async;

	/**
	 * Tests for SocketPool and TimedSocket classes
	 */
	public class SocketPoolTest
	{
		/* change this to connect to a real server */
		private const hostname:String="jmcsrv2";
		private const port:int=27017;
		private var pool:SocketPool;
		
		private var testEnded:Boolean=true;
		
		private static var log:JMCNetLog4JLogger = JMCNetLog4JLogger.getLogger(flash.utils.getQualifiedClassName(SocketPoolTest));
		
		[Before]
		public function setUp():void {
		}
		
		[After]
		public function tearDown():void {
		}
		
		[BeforeClass]
		public static function setUpBeforeClass():void {
			JMCNetLogger.setLogEnabled(true, false);
			JMCNetLogger.setLogLevel(JMCNetLogger.DEBUG);
		}
		
		[AfterClass]
		public static function tearDownAfterClass():void {
		}
		
		[Test(async, timeout=5000)]
		public function simpleTestSocketPool():void {
			log.debug("Calling simpleTestSocketPool");
			pool = new SocketPool(1, 1, 5000);
			verifyPoolInfos(pool.getPoolInfos(), 0, 0, 0);
			
			// Connect
			Async.handleEvent(this, pool, "poolConnected", onSimpleTestPoolConnected, 1000);
			pool.connect(hostname, port);
			
			log.debug("End of simpleTestSocketPool");
		}
		
		private function onSimpleTestPoolConnected(event:Event, ... args):void {
			log.debug("Calling onSimpleTestPoolConnected");
			verifyPoolInfos(pool.getPoolInfos(), 0, 1, 0);
			
			// Ask for a connection
			var socket:TimedSocket = pool.getFreeSocket();
			Assert.assertNotNull(socket);
			verifyPoolInfos(pool.getPoolInfos(), 0, 0, 1);
			
			// Ask for another socket
			var s2:TimedSocket = pool.getFreeSocket();
			Assert.assertNull(s2);
			
			// Release socket
			pool.releaseSocket(socket);
			verifyPoolInfos(pool.getPoolInfos(), 0, 1, 0);
			
			// Disconnect
			Async.handleEvent(this, pool, "poolDisconnected", onSimpleTestPoolDisconnected, 1000);
			pool.disconnect();
			log.debug("End of onSimpleTestPoolConnected");
		}
		
		private function onSimpleTestPoolDisconnected(event:Event, ... args):void {
			log.debug("Calling onSimpleTestPoolDisconnected");
			verifyPoolInfos(pool.getPoolInfos(), 0, 0, 0);
			log.debug("End of onSimpleTestPoolDisconnected");
		}
		
		[Test(async, timeout=10000)]
		public function complexTestSocketPool():void {
			log.debug("Calling complexTestSocketPool");
			pool = new SocketPool(5, 10, 1000);
			verifyPoolInfos(pool.getPoolInfos(), 0, 0, 0);
			
			// Connect and wait for a PoolConnected event
			Async.proceedOnEvent(this, pool, "poolConnected", 1000);
			pool.connect(hostname, port);
			log.debug("After connect");
			
			// Wait that all socket are connected
			var t:Timer = new Timer(1000, 1);
			t.start();
			Async.handleEvent(this, t, TimerEvent.TIMER, onComplexPoolConnected, 2000);
			log.debug("End of complexTestSocketPool");
		}
		
		private function onComplexPoolConnected(event:Event, ...args):void {
			log.debug("Calling onComplexPoolConnected");
			var pi:PoolInfos = pool.getPoolInfos();
			Assert.assertEquals(5, pi.nbFreeSockets);
			Assert.assertEquals(0, pi.nbInCreationSockets);
			
			// Ask for 5 connections
			for (var i:int=0; i< 5;i++) {
				var socket:TimedSocket = pool.getFreeSocket();
				Assert.assertNotNull(socket);
				Assert.assertTrue(pool.getPoolInfos().nbInUseSockets == (i+1));
			}
			
			var t:Timer = new Timer(500,1);
			t.start();
			Async.handleEvent(this, t, TimerEvent.TIMER, onVerifyComplexPool1, 7000);
			log.debug("End of onComplexPoolConnected");
		}
		
		private function onVerifyComplexPool1(event:Event, ...args):void {
			log.debug("Calling onVerifyComplexPool1");
			// 4 new sockets has been instanciated and connected (3 when there is one socket left and one more when the is no more socket left
			verifyPoolInfos(pool.getPoolInfos(), 0, 4, 5);
			
			// We wait for timeout
			var t:Timer = new Timer(6000,1);
			t.start();
			Async.handleEvent(this, t, TimerEvent.TIMER, onVerifyComplexPool2, 7000);
			log.debug("End of onVerifyComplexPool1");
		}
		
		// All active socket have timeouted and new socket are available (there is now 9 sockets)
		private function onVerifyComplexPool2(event:Event, ...args):void {
			log.debug("Calling onVerifyComplexPool2");
			verifyPoolInfos(pool.getPoolInfos(), 0, 9, 0);
			// Disconnect
			Async.handleEvent(this, pool, "poolDisconnected", onComplexPoolDisconnected, 1000);
			pool.disconnect();
			log.debug("End of onVerifyComplexPool2");
		}
			
		// All socket are disconnected (inCreation)
		private function onComplexPoolDisconnected(event:Event, ...args):void {
			log.debug("Calling onComplexPoolDisconnected");
			verifyPoolInfos(pool.getPoolInfos(), 0, 0, 0);
			log.debug("End of onComplexPoolDisconnected");
		}
		
		private function verifyPoolInfos(infos:PoolInfos, nbInCreation:int, nbFree:int, nbInUse:int):void {
			log.debug("Calling verifyPoolInfos");
			Assert.assertEquals(nbInCreation, infos.nbInCreationSockets);
			Assert.assertEquals(nbFree, infos.nbFreeSockets);
			Assert.assertEquals(nbInUse, infos.nbInUseSockets);
			log.debug("End of verifyPoolInfos");
		}
		
	}
}
